package com.boarsoft.config.client;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.common.Util;
import com.boarsoft.common.util.StreamUtil;
import com.boarsoft.config.core.ConfigListener;
import com.boarsoft.config.core.ConfigVarSync;

/**
 * ConfigVarSync接口的客户端默认实现，使用properties文件存储配置<br>
 * 接收到新配置变量后，仅更新配置文件
 * 
 * @author Mac_J
 *
 */
public class PropVarSyncImpl implements ConfigVarSync {
	private static final Logger log = LoggerFactory.getLogger(PropVarSyncImpl.class);

	/** */
	protected Map<String, Properties> propMap = new HashMap<String, Properties>();
	/** */
	protected Map<String, ConfigListener> configListenerMap;

	@PostConstruct
	public void init() {
		for (String group : configListenerMap.keySet()) {
			Properties prop = new Properties();
			this.load(group, prop);
			propMap.put(group, prop);
		}
	}

	protected void load(String group, Properties prop) {
		ConfigListener cl = configListenerMap.get(group);
		// deploy path
		String rp = new StringBuilder().append("/")//
				.append(group).append(".properties").toString();
		// absolute path
		String ap = null;
		try {
			ap = cl.getAbosultePath(rp);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
		log.warn("Load config group {} from {}", group, ap);
		InputStream fis = null;
		try {
			fis = new FileInputStream(new File(ap));
			prop.load(fis);
		} catch (IOException e) {
			log.error("Error on load properties {}", rp, e);
		} finally {
			StreamUtil.close(fis);
		}
	}

	protected boolean save(String group, Properties prop) {
		ConfigListener cl = configListenerMap.get(group);
		// relative path
		String rp = new StringBuilder().append("/")//
				.append(group).append(".properties").toString();
		// absolute path
		String ap = new StringBuilder(cl.getAbosoluteDir())//
				.append(rp).toString();
		log.warn("Save config group {} to {}", group, ap);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(new File(ap));
			prop.store(fos, Util.getStdmfDateTime());
			return cl.onReady(rp);
		} catch (IOException e) {
			log.error("Error on load properties {}", ap, e);
			return false;
		} finally {
			StreamUtil.close(fos);
		}
	}

	@Override
	public Object get(String group, String key) {
		Properties prop = propMap.get(group);
		if (prop == null) {
			return null;
		}
		return prop.get(key);
	}

	@Override
	public boolean put(String group, Map<String, String> items) {
		Properties prop = propMap.get(group);
		if (prop == null) {
			return false;
		}
		// 重新读取，确保内存中的值与文件中的值一致再改
		this.load(group, prop);
		prop.putAll(items);
		return this.save(group, prop);
	}

	@Override
	public boolean delete(String group, String key) {
		Properties prop = propMap.get(group);
		if (prop == null) {
			return false;
		}
		prop.remove(key);
		return this.save(group, prop);
	}

	@Override
	public Map<String, Object> get() {
		Map<String, Object> rm = new HashMap<>();
		rm.putAll(propMap);
		return rm;
	}

	public Map<String, Properties> getPropMap() {
		return propMap;
	}

	public void setPropMap(Map<String, Properties> propMap) {
		this.propMap = propMap;
	}

	public Map<String, ConfigListener> getConfigListenerMap() {
		return configListenerMap;
	}

	public void setConfigListenerMap(Map<String, ConfigListener> configListenerMap) {
		this.configListenerMap = configListenerMap;
	}
}